﻿using EntitiesGenerator.Dtos;
using EntitiesGenerator.Utils;
using EnvDTE;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EntitiesGenerator
{
    public partial class MainForm : Form
    {
        public MainForm(SelectedProject selectedProject)
        {
            InitializeComponent();
            this._SelectedProject = selectedProject;
        }

        /// <summary>
        /// 当前选择的项目
        /// </summary>
        private SelectedProject _SelectedProject = null;

        /// <summary>
        /// 当前正在使用的连接字符串
        /// </summary>
        private string _CurrrentConnectionString = null;

        /// <summary>
        /// 所有的表
        /// </summary>
        private List<string> _Tables = null;

        #region private method

        private void SaveLastData()
        {
            LastDataConfiguration.Instance.ConnectionString = txtConn.Text;
            LastDataConfiguration.Instance.EntitiesSavePath = txtSavePath.Text;
            LastDataConfiguration.Instance.NameSpace = txtNamespace.Text;
            LastDataConfiguration.Instance.InheritClassName = txtBaseType.Text;

            LastDataConfiguration.Instance.Save();
        }

        private void InitLastData()
        {
            if (!LastDataConfiguration.Instance.ConnectionString.IsNullOrWhiteSpace())
                txtConn.Text = LastDataConfiguration.Instance.ConnectionString;
            txtSavePath.Text = LastDataConfiguration.Instance.EntitiesSavePath;
            txtNamespace.Text = LastDataConfiguration.Instance.NameSpace;
            txtBaseType.Text = LastDataConfiguration.Instance.InheritClassName;
        }

        private string ShowTableName(string tableName)
        {

            if (Exists(tableName))
                return tableName + "[已存在]";
            return tableName;
        }

        private bool Exists(string tableName)
        {
            return _SelectedProject.AllCsFilenamesWithoutExtension.Any(r => r.Equals(tableName));
        }

        private IEnumerable<string> GetCheckedTables()
        {
            foreach (var item in clsbTables.CheckedItems)
                yield return item.ToString().Replace("[已存在]", "");
        }

        private void Search()
        {
            if (_Tables == null)
                return;
            clsbTables.Items.Clear();


            IEnumerable<string> query = _Tables;
            if (!txtSearch.Text.IsNullOrWhiteSpace())
            {

                query = query.Where(r => r.Contains(txtSearch.Text.Trim(), StringComparison.OrdinalIgnoreCase));
            }
            if (cbsGetExists.Checked)
            {
                query = query.Where(r => Exists(r));
            }
            query = query.Select(ShowTableName);
            clsbTables.Items.AddRange(query.ToArray());
        }

        //private Action<string> ShowBuildMsgAction =>
        //    (msg) =>
        //        {

        //            if (!txtMsg.Text.IsNullOrWhiteSpace())
        //                txtMsg.AppendText("\r\n");
        //            txtMsg.AppendText(msg);
        //            txtMsg.ScrollToCaret();
        //        };

        private async Task ShowBuildMsg(string msg)
        {
            //txtMsg.Invoke(ShowBuildMsgAction, msg);
            await Task.Run(() =>
             {
                 if (!txtMsg.Text.IsNullOrWhiteSpace())
                     txtMsg.AppendText("\r\n");
                 txtMsg.AppendText(msg);
                 txtMsg.ScrollToCaret();
             });
        }


        #endregion

        #region events

        private void btnConn_Click(object sender, EventArgs e)
        {
            if (txtConn.Text.IsNullOrWhiteSpace())
            {
                MessageBox.Show("连接字符串不能为空,无法连接!");
                return;
            }
            try
            {
                _CurrrentConnectionString = txtConn.Text;
                var tables = Sql.GetAllTable(_CurrrentConnectionString);

                clsbTables.Items.Clear();

                clsbTables.Items.AddRange(tables.Select(ShowTableName).ToArray());
                _Tables = tables;
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接出现错误:" + ex.Message);
            }
        }

        private async void btnBuild_Click(object sender, EventArgs e)
        {
            if (_CurrrentConnectionString.IsNullOrWhiteSpace())
            {
                MessageBox.Show("当前连接为空,请重新连接数据库!");
                return;
            }
            try
            {

                string nameSpace = "";
                if (txtNamespace_Prefix.Text.IsNullOrWhiteSpace())
                    nameSpace = txtNamespace.Text.Trim();
                else
                {
                    nameSpace = txtNamespace_Prefix.Text.Trim();

                    if (!txtNamespace.Text.IsNullOrWhiteSpace())
                    {
                        nameSpace += "." + txtNamespace.Text.Trim();
                    }
                }

                if (nameSpace.IsNullOrWhiteSpace())
                {
                    MessageBox.Show("命名空间都为空,不太好吧....");
                    return;
                }

                var checkedtable = GetCheckedTables().ToList();
                await ShowBuildMsg("正在读取数据........");

                var tables = await Task.Run(() =>
                 {
                     return checkedtable.Select(r => new Table(_CurrrentConnectionString, r)).ToList();
                 });

                ProjectItem lastItem = null;
                if (!txtSavePath.Text.IsNullOrWhiteSpace())
                    lastItem = this._SelectedProject.ProjectDte.AddFolderToProject(txtSavePath.Text);

                var saveDir = Path.Combine(_SelectedProject.ProjectDirectoryName, txtSavePath.Text);
                if (!Directory.Exists(saveDir))
                    Directory.CreateDirectory(saveDir);


                //放个临时文件夹 再用AddFileFromCopy的方式 添加到项目中,增加了IO操作
                //实在没找到用什么方法可以直接添加一个现有的文件

                string generatorTempDir = "c:\\generator_temp";
                bool shouldDeleteTempDir = false;
                if (!Directory.Exists(generatorTempDir))
                {
                    shouldDeleteTempDir = true;
                    Directory.CreateDirectory(generatorTempDir);
                }

                #region 实体类创建

                foreach (var item in tables)
                {

                    await ShowBuildMsg($"开始为您创建实体:\"{item.TableName}.cs\"");

                    //这里无需等待
                    await Task.Run(async () =>
                    {
                        try
                        {
                            string classContent = item.GeneralEntityClass(nameSpace, txtBaseType.Text);
                            var fileFullName = Path.Combine(saveDir, item.TableName + ".cs");

                            if (!File.Exists(fileFullName))
                            {
                                var fileTempFullName = Path.Combine(generatorTempDir, item.TableName + ".cs");

                                File.WriteAllText(fileTempFullName, classContent, Encoding.UTF8);
                                if (lastItem != null)
                                    lastItem.AddFilesToProject(fileTempFullName);
                                else
                                    this._SelectedProject.ProjectDte.AddFilesToProject(fileTempFullName);
                                _SelectedProject.ProjectDte.Save();

                                File.Delete(fileTempFullName);
                            }
                            else
                            {
                                File.WriteAllText(fileFullName, classContent, Encoding.UTF8);
                            }

                            await ShowBuildMsg($"实体文件[{item.TableName}.cs]创建完成");
                        }
                        catch (Exception ex)
                        {
                            await ShowBuildMsg($"创建实体文件[{item.TableName}.cs]出现错误:{ex.Message}");
                        }
                    });
                }

                #endregion

                #region dbcontext创建

                if (cbsBuildContext.Checked)
                {
                    string contextName = txtContextName.Text.IsNullOrWhiteSpace() ? "MyDbContext" : txtContextName.Text.Trim();

                    StringBuilder sb = new StringBuilder();
                    tables
                        .Select(r => string.Format(EntityTemplateConst.ContextProperty, r.TableName))
                        .ToList()
                        .ForEach(r => { sb.AppendLine(); sb.AppendLine(r); });

                    string contextClassContent = EntityTemplateConst.DbContextTemplate
                           .Replace("{NameSpace}", nameSpace)
                           .Replace("{ContextName}", contextName)
                           .Replace("{Properties}", sb.ToString());


                    try
                    {
                        var fileFullName = Path.Combine(saveDir, contextName + ".cs");
                        await ShowBuildMsg($"正在为您创建:\"{contextName}.cs\"");

                        if (!File.Exists(fileFullName))
                        {
                            var fileTempFullName = Path.Combine(generatorTempDir, contextName + ".cs");

                            File.WriteAllText(fileTempFullName, contextClassContent, Encoding.UTF8);

                            if (lastItem != null)
                                lastItem.AddFilesToProject(fileTempFullName);
                            else
                                this._SelectedProject.ProjectDte.AddFilesToProject(fileTempFullName);
                            _SelectedProject.ProjectDte.Save();

                            File.Delete(fileTempFullName);
                        }
                        else
                        {
                            File.WriteAllText(fileFullName, contextClassContent, Encoding.UTF8);
                        }
                    }
                    catch (Exception ex)
                    {
                        await ShowBuildMsg($"创建DbContext文件[{contextName}.cs]出现错误:{ex.Message}");
                    }
                }

                #endregion

                if (shouldDeleteTempDir)
                    Directory.Delete(generatorTempDir, true);
                SaveLastData();

                await ShowBuildMsg("已为您创建完成!");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void txtSearch_Leave(object sender, EventArgs e)
        {
            Search();
        }

        private void txtSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                Search();
        }

        private void cbxAll_CheckedChanged(object sender, EventArgs e)
        {
            if (_Tables == null)
                return;

            for (int i = 0; i < clsbTables.Items.Count; i++)
            {
                clsbTables.SetItemChecked(i, cbxAll.Checked);
            }
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (_Tables == null)
                return;

            for (int i = 0; i < clsbTables.Items.Count; i++)
            {
                clsbTables.SetItemChecked(i, !clsbTables.GetItemChecked(i));
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            try
            {
                InitLastData();
                txtNamespace_Prefix.Text = _SelectedProject.ProjectName;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            txtContextName.ReadOnly = !cbsBuildContext.Checked;
        }

        private void cbsGetExists_CheckedChanged(object sender, EventArgs e)
        {
            Search();
        }
        #endregion
    }
}
